#pragma once
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "d3dx9.lib")

#include <windows.h>
#include <windowsx.h>
#include <atlbase.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <list>

#include "MeshHierarchy.h"
#include "structures.h"

using namespace std;

typedef struct _myD3DBuffer {
	DWORD fvf;
	UINT fvfsize;
	D3DPRIMITIVETYPE type;
	UINT primitiveCount;
	D3DXMATRIX *transform;
	LPDIRECT3DVERTEXBUFFER9 vb;
	D3DMATERIAL9 mat;
	LPDIRECT3DTEXTURE9 ptex1;
}myD3DBuffer, *lpmyD3DBuffer;

typedef struct _myD3DMesh {
	DWORD subsets;
	D3DMATERIAL9 *mats;
	D3DXMATRIX *transform;
	LPDIRECT3DTEXTURE9 *texs;
	LPD3DXMESH mesh;
} myD3DMesh, *lpmyD3DMesh;

typedef struct _myD3DTexture {
	LPDIRECT3DTEXTURE9 tex;
} myD3DTexture, *lpmyD3DTexture;

class myD3D {
	// pointer to directX
	LPDIRECT3D9 d3d;
	// pointer to directX Device
	LPDIRECT3DDEVICE9 d3ddev;
	// initial parameters of directX Device
	D3DPRESENT_PARAMETERS d3dpp;
	// Effects
	LPD3DXEFFECT effect;

	// skinning and bones
	LPD3DXFRAME	frame;
	D3DXMATRIX *boneMatrices;
	UINT maxBones;
	D3DXMESHCONTAINER_EXTENDED* firstMesh;
	void SetupBoneMatrices(LPDIRECT3DDEVICE9 dev, D3DXFRAME_EXTENDED *pFrame, LPD3DXMATRIX pParent);
	void DrawFrame(LPD3DXFRAME _frame) const;
	void DrawMeshContainer(LPD3DXMESHCONTAINER meshContainerBase, LPD3DXFRAME frameBase) const;
	void UpdateBones();

	// animated mesh stuff
	LPD3DXANIMATIONCONTROLLER anim;
	// pointer to a directX window
	HWND hWnd;
	// list of primitives to draw
	list<lpmyD3DBuffer> prims;
	// list of meshes to be drawn
	list<lpmyD3DMesh> meshes;
	// list of textures
	list<lpmyD3DTexture> textures;
public:
	myD3D();
	~myD3D();

	// TEMP get directX device
	LPDIRECT3DDEVICE9 getDev() { return d3ddev; }

	// a MUST finction to create directX instance
	bool Init(HWND _hWnd, bool fullscreen, int w, int h);
	// set LookAt
	bool setLookAt();
	bool setLookAt(D3DXVECTOR3 *camPosition, D3DXVECTOR3 *lookAtPosition, D3DXVECTOR3 *upDirection);
	bool setLookAt(D3DXMATRIX *view);
	// set view perspective
	bool setPerspective();
	bool setPerspective(float fovRadian, float aspect_WOverH, float z_near, float z_far);
	bool setPerspective(D3DXMATRIX *projectionMatrix);
	//setup light in the scene
	void setLight(DWORD index, bool makeOn, D3DLIGHT9 *light);
	// turn on/off 3d lighting
	void light3d(bool on);
	// change renderer state do custom one
	bool setRendState(D3DRENDERSTATETYPE state, DWORD value);
	// add texture (with colormask)
	LPDIRECT3DTEXTURE9 addTextureFromFile(LPCWSTR path, D3DCOLOR *colorMaskKey = NULL);
	// add another primitive to renderer pipeline
	bool addPrimitive(void *data, DWORD _fvf, UINT _fvfstructsize, D3DPRIMITIVETYPE _type, 
		UINT count, D3DXMATRIX *_transform, D3DMATERIAL9 *_mat = NULL, LPDIRECT3DTEXTURE9 tex1 = NULL); 
	bool addMesh(LPD3DXMESH *_mesh, DWORD _subsets, D3DXMATRIX *_transform = NULL, 
		D3DMATERIAL9 *_mats = NULL, LPDIRECT3DTEXTURE9 *_texs = NULL);
	// load a mesh (from .x file) with animation and bones
	bool addXAnimatedMeshFile(LPCWSTR path);
	// load simple .x file
	bool addXFile(LPCWSTR path, D3DXMATRIX *_globalTransform = NULL);
	// loading shader file
	bool loadShaderFile(LPCWSTR path);
	
	// function to render frame
	void RenderFrame();
};